import React, { useState, useEffect, memo, useRef } from "react"
import logo from "./logo.svg"
import "./App.css"
import {
  createSetAction,
  createToggleAction,
  createRemoveAction,
  createAddAction,
} from "./action"
import reducer from "./reducers"

const storageKey = "_$todo_"

let store = {
  todos: [],
  incrementCount: 0,
}

const bindActionCreators = (actionCreators, dispatch) => {
  const result = {}
  const keys = Object.keys(actionCreators)
  keys.forEach((key) => {
    result[key] = function (...args) {
      dispatch(actionCreators[key](...args))
    }
  })
  return result
}

const Control = memo(function Control({ addTodo }) {
  const inputRef = useRef()
  const onSubmit = (e) => {
    e.preventDefault()
    const newText = inputRef.current.value.trim()
    if (!newText) return
    addTodo(newText)

    inputRef.current.value = ""
  }
  return (
    <div className="control">
      <h1>
        <img src={logo} alt="" width="40" />
        <span>Todo</span>
      </h1>
      <form onSubmit={onSubmit}>
        <input ref={inputRef} className="new-todo" />
      </form>
    </div>
  )
})

const Todos = memo(function Todos({ todos, removeTodo, toggleTodo }) {
  return (
    <ul className="todos">
      {todos.map((todo) => {
        return (
          <TodoItem
            key={todo.id}
            todo={todo}
            toggleTodo={toggleTodo}
            removeTodo={removeTodo}
          />
        )
      })}
    </ul>
  )
})

const TodoItem = memo(function TodoItem({ todo, toggleTodo, removeTodo }) {
  const { id, text, complete } = todo
  const onChange = (e) => {
    toggleTodo(id)
  }
  const onRemove = (e) => {
    removeTodo(id)
  }
  return (
    <li className="todo-item">
      <input type="checkbox" onChange={onChange} checked={complete} />
      <label className={complete ? "complete" : ""}>{text}</label>
      <button onClick={onRemove}>X</button>
    </li>
  )
})

function TodoList() {
  const [todos, setTodos] = useState([])
  const [incrementCount, setIncrementCount] = useState(0)

  const dispatch = (action) => {
    const setters = {
      todos: setTodos,
      incrementCount: setIncrementCount,
    }

    if (typeof action === "function") {
      action(dispatch, () => store)

      return
    }

    const newState = reducer(store, action)

    Object.keys(newState).forEach((key) => {
      setters[key](newState[key])
    })
  }

  useEffect(() => {
    Object.assign(store, {
      todos,
      incrementCount,
    })
  }, [todos, incrementCount])

  useEffect(() => {
    const todos = JSON.parse(window.localStorage.getItem(storageKey)) || []

    dispatch(createSetAction(todos))
    // eslint-disable-next-line
  }, [])

  useEffect(() => {
    window.localStorage.setItem(storageKey, JSON.stringify(todos))
  }, [todos])

  return (
    <div className="todo-list">
      <Control
        {...bindActionCreators(
          {
            addTodo: createAddAction,
          },
          dispatch
        )}
      />
      <Todos
        {...bindActionCreators(
          {
            removeTodo: createRemoveAction,
            toggleTodo: createToggleAction,
          },
          dispatch
        )}
        todos={todos}
      />
    </div>
  )
}

export default TodoList
